%{

using namespace std;
#include "commun.h"

int xml_wrap(void);
void xml_error(XMLArbre** arbre, char *msg);
int xml_lex(void);

extern char* dtd_fileName;

%}

%union {
   char * s;
   string * st;
   ElementName * en;  /* le nom d'un element avec son namespace */
   vector<Item*> * liste_items;
   Element * el;
   XMLArbre * xml_arbre;
   vector<string> * liste_string; 
   Attribut * attr;
   vector<Attribut*> * liste_attributs;
}

%token EQ SLASH CLOSE CLOSESPECIAL DOCTYPE
%token <s> ENCODING STRING DATA COMMENT IDENT NSIDENT
%token <en> NSSTART START STARTSPECIAL END NSEND

%type <liste_items> content_opt close_content_and_end content
%type <el> xml_element
%type <en> start
%type <xml_arbre> document
%type <st> declaration declarations_opt
%type <liste_string> misc_seq_opt
%type <s> comment
%type <attr> attribut
%type <liste_attributs> attributs_opt

%parse-param {XMLArbre ** arbre}

%%
main
 : document	{ *arbre = $1; }
 ;

document
 : declarations_opt xml_element misc_seq_opt  { $$ = new XMLArbre();  $$->setDeclaration($1); $$->setRacine($2); $$->setCommentaires($3); }
 ;
misc_seq_opt
 : misc_seq_opt comment { $$ = $1; $$->push_back(string($2)); free($2); }
 | /*empty*/ { $$ = new vector<string>; }
 ;
comment
 : COMMENT { $$ = $1; }
 ;

declarations_opt
 : declaration { $$ = $1; }
 | /*empty*/  { $$ = new string(""); }
 ;
 
declaration
 : DOCTYPE IDENT IDENT STRING CLOSE
	{ dtd_fileName = $4; 
	  $$ = new string("<!DOCTYPE"); 
	  $$->append(" "); $$->append($2); 
          $$->append(" "); $$->append($3); 
          $$->append(" '"); $$->append($4);
	  $$->append("'>");}
 ;

xml_element
 : start attributs_opt content { $$ = new ContentElement(new string($1->second), new string($1->first)); $$->setAttributs($2); $$->setItems($3); } 
 | start attributs_opt empty { $$ = new EmptyElement(new string($1->second), new string($1->first)); $$->setAttributs($2); } 
 ;

attributs_opt
 : attributs_opt attribut { $$ = $1; $$->push_back($2); }
 | /*empty*/ { $$ = new vector<Attribut*>; }
 ;

attribut 
 : IDENT EQ STRING { $$ = new Attribut(new string($1), new string($3)); }
 ;

start
 : START { $$ = $1; }		
 | NSSTART { $$ = $1; }
 ;

empty
 : SLASH CLOSE	
 ;

content
 : close_content_and_end CLOSE { $$ = $1; }
 ;

close_content_and_end
 : CLOSE content_opt END { $$ = $2; }
 | CLOSE content_opt NSEND { $$ = $2; }
 ;

content_opt 
 : content_opt DATA { $$ = $1; $$->push_back(new Data(new string($2))); }	
 | content_opt comment { $$ = $1; $$->push_back(new Data(new string($2))); } //TODO: what should we do with the comment????
 | content_opt xml_element { $$ = $1; $$->push_back($2); }
 | /*empty*/ { $$ = new vector<Item*>; }
 ;

%%

int xml_wrap(void)
{
  return 1;
}

void xml_error(XMLArbre** arbre, char *msg)
{
  fprintf(stderr, "%s\n", msg);
} 
